SecretsManager CloudFormation으로 작성해보기!

SecretsManager CloudFormation으로 작성해보기!

Clock Icon2022.05.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

소개

안녕하세요! 클래스메소드 금상원 입니다. 이번 블로그에서는 SecretsManager를 CloudFormation을 이용하여 작성하는 방법에 대해 해보도록 하겠습니다.

콘솔 화면에서 SecretsManager작성 하는 방법에 대하여

SecretsManager작성하기

SecretString JSON 에 램덤으로 생산되는 패스워드를 가진 새로운 SecretsManager를 작성합니다.

이 정보에는 암호, 사용자 이름 및 암호와 같은 자격 증명 집합, OAuth 토큰 또는 Secrets Manager에서 암호화된 형식으로 정보를 저장 합니다.

RDSRotationSecret: 
    Type: AWS::SecretsManager::Secret
    Properties:
      Description: "test rds instance secret"
      Name: "/aws/rds/cluster/test/keum"
      GenerateSecretString:
        SecretStringTemplate: '{"username": "admin"}'
        GenerateStringKey: "password"
        PasswordLength: 32
        ExcludeCharacters: '"@/\'

GenerateSecretString : 비밀번호를 생성하고 SecretsManager에 저장하는 방법을 지정하는 구조입니다.

SecretStringTemplate : 생성된 문자열이 RDS와 일치되여야하는 부분이기때문에 RDS의 MasterUsername을 입력해줍니다.

GenerateStringKey : 키/값 쌍의 JSON 키 이름입니다. 여기서 값은 생성된 RDS의 비밀번호입니다.

PasswordLength : 비밀번호의 길이를 지정합니다.

ExcludeCharacters : 암호에 포함하지 않는 문자를 지정합니다. (문제가 되는 문자들을 주로 기입합니다.)

RDS와 연결하기

RDS와 생성한 SecretsManager를 연결하여 해당 RDS의 비밀번호를 관리 합니다.

SecretRDSInstanceAttachment:
    Type: AWS::SecretsManager::SecretTargetAttachment
    Properties:
      SecretId: !Ref RDSRotationSecret
      TargetId: !Ref RDSCluster
      TargetType: AWS::RDS::DBCluster

SecretId : 생성된 SecretsManager의 ID를 입력합니다. (!Ref를 사용하는 것을 추천합니다.)

TargetId : 연결할 서비스의 ID를 입력합니다. (!Ref나 !ImportValue를 사용하는 것을 추천합니다.)

TargetType : 연결할 서비스의 유형을 링크 에서 확인 후 입력합니다.

로테이션 작성하기

보안 암호에 대한 교체 일정 및 Lambda 교체 함수를 설정합니다.

MySecretRotationSchedule:
    Type: AWS::SecretsManager::RotationSchedule
    DependsOn: SecretRDSInstanceAttachment
    Properties:
      SecretId: !Ref RDSRotationSecret
      HostedRotationLambda:
        RotationType: "PostgreSQLSingleUser"
        RotationLambdaName: "SecretsManagerRotation"
        VpcSecurityGroupIds: !ImportValue SMSG
        VpcSubnetIds: "subnet-bb293dd2" 
      RotationRules:
        Duration: "1h"
        ScheduleExpression: "cron(0 17 ? * FRI *)"

SecretId : 로테이션을 연결할 SecretsManager의 ID를 입력합니다. (!Ref를 사용하는 것을 추천합니다.)

HostedRotationLambda : Secrets Manager 교체 함수 템플릿 중 하나를 기반으로 새 Lambda 교체 함수를 생성합니다 .

RotationType : 회전 기능의 기반이 되는 회전 템플릿을 링크에서 확인한 후 입력 해주세요.

VpcSecurityGroupIds : 람다에 사용할 보안그룹ID을 입력합니다.

VpcSubnetIds : 람다를 배치할 Subnet의 ID를 입력합니다.

RotationRules : Secrets Manager에 대한 Rotation 구성을 정의하는 구조입니다.

Duration : Rotation을 실행하는 시간의 길이입니다. Secrets Manager는 이 기간 동안 언제든지 암호를 교체합니다.

ScheduleExpression : 암호 교체 일정을 정의합니다. 표현식은 cron()또는 rate() 사용합니다.

전체 코드

AWSTemplateFormatVersion: "2010-09-09"
Description: "Secrets Manager with automatic rotation"
Transform: "AWS::SecretsManager-2020-07-23"
Parameters:
  USERNAME:
    Type: String
    Default: "keum"
    Description: user name
  DBNAME:
    Type: String
    Default: "test"
    Description: DB Name
  DBTYPE:
    Type: String
    Default: "db.r6g.large"
    Description: DB Instance Type
  ENGINE:
    Type: String
    Default: "aurora-postgresql"
    Description: DB Engine
  ENGINEVERSION:
    Type: String
    Default: "13.5"
    Description: DB Engine Version

Resources:

  RDSRotationSecret: 
    Type: AWS::SecretsManager::Secret
    Properties:
      Description: "test rds instance secret"
      Name: "/aws/rds/cluster/test-prd-db-rds-aurora-postgresql/okina"
      GenerateSecretString:
        SecretStringTemplate: '{"username": "keum"}'
        GenerateStringKey: "password"
        PasswordLength: 32
        ExcludeCharacters: '"@/\'

  RDSClusterParameterGroup:
    Type: "AWS::RDS::DBClusterParameterGroup"
    Properties:
      Description: "DB Parameter Group for test-prd-db-rds-aurora-postgresql"
      Family: "aurora-postgresql13"
      Parameters:
        timezone : Asia/Tokyo
        client_encoding: UTF8
      Tags:
        - Key: Name
          Value: "test-prd-db-rds-aurora-postgresql-cluster-dbparametergroup"

  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties: 
      DBSubnetGroupDescription: "DB Subnet Group on Isolated Subnets"
      DBSubnetGroupName: "test-prd-rds-sbng"
      SubnetIds: 
        - !ImportValue PrivateSubnet-a #from subnet.yaml
        - !ImportValue PrivateSubnet-c #from subnet.yaml
      Tags: 
        - Key: Name
          Value: "test-prd-rds-sbng"

  RDSCluster: 
    Type: AWS::RDS::DBCluster
    Properties: 
      DatabaseName: !Ref DBNAME
      Engine: !Ref ENGINE
      EngineMode: "provisioned"
      EngineVersion: !Ref ENGINEVERSION
      DBClusterIdentifier: "test-prd-db-rds-aurora-postgresql"
      MasterUsername: !Join ['', ['{{resolve:secretsmanager:', !Ref RDSRotationSecret, ':SecretString:username}}' ]]
      MasterUserPassword: !Join ['', ['{{resolve:secretsmanager:', !Ref RDSRotationSecret, ':SecretString:password}}' ]]
      DBSubnetGroupName: !Ref DBSubnetGroup
      Port: 5432
      BackupRetentionPeriod: 7
      CopyTagsToSnapshot: true
      PreferredBackupWindow: "16:00-16:30"
      PreferredMaintenanceWindow: "Fri:18:00-Fri:18:30"
      DeletionProtection: true
      EnableCloudwatchLogsExports: 
        - postgresql
      VpcSecurityGroupIds:
        - !ImportValue RDSSG
      DBClusterParameterGroupName: !Ref RDSClusterParameterGroup
      StorageEncrypted: true

  RDSDBParameterGroup: 
    Type: "AWS::RDS::DBParameterGroup"
    Properties: 
      Description: "DB Parameter Group for test-prd-db-rds-aurora-postgresql"
      Family: "aurora-postgresql13"
      Tags:
        - Key: Name
          Value: "test-prd-db-rds-aurora-postgresql-dbparametergroup"

  RDSDBInstance: 
    Type: "AWS::RDS::DBInstance"
    Properties: 
      DBClusterIdentifier: !Ref RDSCluster
      DBInstanceClass: !Ref DBTYPE  
      MultiAZ: false
      AvailabilityZone: "ap-northeast-1a"
      PubliclyAccessible: false
      EnablePerformanceInsights: true
      PerformanceInsightsRetentionPeriod: 7
      AutoMinorVersionUpgrade: true
      PreferredMaintenanceWindow: "Fri:18:30-Fri:19:00"
      DBSubnetGroupName: !Ref DBSubnetGroup
      DBParameterGroupName: !Ref RDSDBParameterGroup
      Engine: !Ref ENGINE
      EngineVersion: !Ref ENGINEVERSION

  SecretRDSInstanceAttachment:
    Type: AWS::SecretsManager::SecretTargetAttachment
    Properties:
      SecretId: !Ref RDSRotationSecret
      TargetId: !Ref RDSCluster
      TargetType: AWS::RDS::DBCluster

  MySecretRotationSchedule:
    Type: AWS::SecretsManager::RotationSchedule
    DependsOn: SecretRDSInstanceAttachment
    Properties:
      SecretId: !Ref RDSRotationSecret
      HostedRotationLambda:
        RotationType: "PostgreSQLSingleUser"
        RotationLambdaName: "SecretsManagerRotation"
        VpcSecurityGroupIds: !ImportValue SMSG # from sg.yaml
        VpcSubnetIds: "subnet-bb293dd2" # ec2 subnet
      RotationRules:
        Duration: "1h"
        ScheduleExpression: "cron(0 17 ? * FRI *)"

마무리

이번 블로그에서는 CloudFormation을 이용하여 AWS ScretsManager를 작성하는 방법에 대해 알아보았습니다.

ScretsManager를 CloudFormation으로 작성 하실려는 분들에게 조금이나마 도움이 되었으면 좋겠습니다.

참고자료

본 블로그 게시글을 보시고 문의 사항이 있으신 분들은 클래스메소드코리아 (info@classmethod.kr)로 연락 주시면 빠른 시일 내 담당자가 회신 드릴 수 있도록 하겠습니다 !

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.